#!/bin/bash

shopt -s extglob

#~ echo "$@" > /tmp/mpv-clip.log # ytfzf url_handler_opts='assdadasdasda' # doesn't work

usage() {
    if [[ "$@" != "" ]]; then
        notify "$@" "Help text in terminal: $x11name -h"
    fi
    echo "
Play URLs with mpv/youtube-dl/yt-dlp:
mpv-clip [options] URL
+ copy URL back to clipboard or primary selection, formatted with media title.

Options:

-a      Play only audio, but open a small controllable window with elapsed/total
        time, and don't disable the screensaver.

-p      Advance in playlist - does not seem to work with youtube currently.
        Does work with e.g. bandcamp.

-Y str  Options to add to mpv --ytdl-raw-options, after a comma. No quality
        control! See 'man mpv' for details.

-y str  Alternate domain that replaces youtube, e.g. \"invidious.snopyta.org\".
        Testing the domain requires 'ping'.

-s str  Override list of subtitle languages to embed. The default is to use
        your locale + English (2 letter ISO 639-1 codes): \"${slang}\". Pass empty
        string \"\" for ALL subtitles, which can be a lot for e.g. youtube.

-c str  How to copy URL+title back to the clipboard - this string must contain
        exactly two letters:
            1. c|p|b    for clipboard, primary selection, or both
            2. b|m|t    for BBCode, markdown or plain text
        Default: 'cb'.

-t int  Network timeout in seconds.  With '-y', this is applied twice
        Default: $timeout

-n      Send desktop notifications.

-i str  Path to icon for notifications.
        Default: ${icon/$HOME/\~}

-E str  Comma separated list of variables and their values. This option exists
        to read ytfzf's values passed to URL handlers, namely \$video_pref,
        \$is_detach and \$is_audio_only

-h      This text.
"
    exit 1
}
notify() {
    ((notify>0)) && notify-send -i $icon -- "$@" || \
    echo "$@"
}
clipboard() {
    [[ "$clipboard" == "" ]] && return
    # variables URL and title must be defined
    case $markup in
        b) out="[url=${URL}]${title}[/url]"
        ;;
        m) out="[${title}](${URL})"
        ;;
        t) out="$title
$URL"
        ;;
    esac
    case $clipboard in
        c) echo -n "$out" | xsel -b
        ;;
        p) echo -n "$out" | xsel -p
        ;;
        b) echo -n "$out" | xsel -b
           echo -n "$out" | xsel -p
        ;;
    esac
}

x11name="mpv-clip" # xprop class name to be used by xdotool and optionally window manager
icon="/usr/share/icons/Papirus/48x48/apps/multimedia-video-player.svg"
bbcode=0 # fill clipboard with BBcode instead of plain text
notify=0
ytmirror=""
timeout=5 # network timeout in seconds
ytdlrawopts='write-info-json='
clipboard='c'
cbtext="clipboard"
markup='t'

for dep in mpv; do
    type "$dep" >/dev/null || usage
done

slang="${LANG%%_*}"
slang="${slang,,}";
[[ "$slang" == en ]] || slang="${slang},en"

# Just to initialize the array...
#~ opts=( --force-window=yes --ytdl=yes --ytdl-format=ytdl --script-opts=ytdl_hook-try_ytdl_first=yes --script-opts=ytdl_hook-all_formats=yes --script-opts=ytdl_hook-thumbnails=best --script-opts=ytdl_hook-use_manifests=yes ) # mpv options for all use cases
opts=( --force-window=yes --ytdl=yes --ytdl-format=ytdl --script-opts=ytdl_hook-try_ytdl_first=yes ) # mpv options for all use cases

while getopts apY:y:s:c:t:i:hnE: opt; do
    case $opt in
        a)  geometry="33%x30+0+0"
            opts=( ${opts[@]} --vid=no --sub=no
            --osd-scale-by-window=no --no-osd-bar --no-osc
            --osd-msg1=\${time-pos}/\${duration}
            --osd-font-size=28 --osd-font=monospace --background=.1/.1/.1
            --osd-color=.9/.9/.9 --osd-border-size=0
            --osd-margin-y=0 --osd-margin-x=5 --no-stop-screensaver )
            x11name="${x11name}-audioonly"
        ;;
        p)  opts=( ${opts[@]} --ytdl-raw-options=ignore-errors=,yes-playlist= ) # as of 2020-10-19, this does not seem to work at all with youtube (or invidious mirrors)
            x11name="${x11name}-playlist"
        ;;
        Y)  
            ytdlrawopts=",$OPTARG"
        ;;
        y)  ytmirror="$OPTARG" # will use "$ytmirror" instead of "www.youtube.com" or "youtu.be"
            for dep in host ping; do type $dep >/dev/null || usage; done
        ;;
        s)  slang="$OPTARG" # comma separated list of subtitle languages - pass empty string '' or "" to get ALL subtitles
        ;;
        c)  (( "${#OPTARG}" != 2 )) && usage "Invalid argument -$opt $OPTARG"
            clipboard="${OPTARG:0:1}"
            markup="${OPTARG:1:1}"
            [[ "$clipboard" =~ ^(c|p|b)$ ]] && [[ "$markup" =~ ^(b|m|t)$ ]] || usage "Invalid argument -$opt $OPTARG"
            type xsel >/dev/null || usage
            case $clipboard in
                c) cbtext="clipboard" ;;
                p) cbtext="primary selection" ;;
                b) cbtext="clipboard and primary selection" ;;
            esac
        ;;
        t)  timeout="$OPTARG"
            [[ "$OPTARG" =~ ^[1-9][0-9]*$ ]] || usage "-$opt: Invalid number: $OPTARG (must be a positive integer)"
        ;;
        i)  icon="$OPTARG"
            [ -r "$OPTARG" ] || usage "-$opt: Cannot read $OPTARG"
        ;;
        n)  notify=1
        ;;
        E)  
            echo "$OPTARG" >> /tmp/mpv-clip.log
        ;;
        h|*)  usage
        ;;
    esac
done
shift $((OPTIND-1))
cbtext="(copied URL+title to $cbtext)"

# first things first...
URL="$1"
# remove leading/trailing whitespace:
URL="${URL#[[:space:]]*}"
URL="${URL%[[:space:]]*}"
# replace the rest with %20 (urlencode for dummies)
URL="${URL//[[:space:]]/%20}"
# check if it's actually an http URL

[[ "$URL" =~ ^(https?|ftp|file)://* ]] || URL="https://$URL" # try to fix it
[[ "$URL" == ?*\.?* ]] || usage "$URL is not a valid URL" # must contain at least one dot

# silently drop notifications if this is not available
type notify-send >/dev/null 2>&1 || [[ "$notify" == 0 ]]

if [[ "$ytmirror" != "" ]]; then
    ytdomains=( www.youtube.com youtube.com m.youtube.com youtu.be )
    for domain in "${ytdomains[@]}"; do
        if [[ "$URL" =~ ^(https?)://$domain/* ]]; then
            if ping -c1 -n -w"$timeout" "$ytmirror" >/dev/null; then
                URL="${URL/$domain/$ytmirror}" && break
            else
                ytmirror=''
            fi
            break
        fi
    done
fi

# introducing raw options passed to youtube-dl
if [[ "$x11name" == *"-audioonly" ]]; then
    ytdlrawopts="${ytdlrawopts},format=bestaudio"
fi
#~ ytdlrawopts="${ytdlrawopts},socket-timeout=$timeout"
[[ "$slang" == "" ]] || ytdlrawopts="${ytdlrawopts},sub-lang=\"$slang\""

# for indentifying windows (and notifications)
x11name="$x11name-$(printf '%(%H:%M:%S)T')"

# Building the command line
opts=( ${opts[@]}
--network-timeout=$timeout
--ytdl-raw-options="${ytdlrawopts#,}"
--x11-name="$x11name"
--quiet
--no-msg-color
--no-input-terminal --term-playing-msg='media-title: ${media-title}'
--no-resume-playback
--watch-later-directory=/dev/null
)

((notify>1)) && notify "Trying: $URL" "$x11name"
echo "Trying: $URL"

coproc mpv "${opts[@]}" "$URL"
error=0
while read -r -u "${COPROC[0]}" line; do
    echo "$line"
    if [[ "$line" == *"media-title: "* ]]; then
        title="${line#*media-title: }"
        notify "$title" "$x11name $cbtext"
        clipboard
    #~ often there are http errors, but playback continues regardless. so let's drop it.
    #~ elif [[ "$line" == *"HTTP error"* ]] || [[ "$line" == *"ytdl_hook: ERROR:"* ]]; then
    elif [[ "$line" == *"ytdl_hook: ERROR:"* ]]; then
        line="${line%%; please report this issue*}"
        notify=1; error=1
        notify "$line" "$x11name"
    fi
done
[[ "$error" == 1 ]] && exit 1
notify "That was: $title" "Exiting $x11name $cbtext"
